参考博客链接: 🔗 这个
1. 什么是Word Embedding
在机器学习和深度学习的任务中,我们都无法直接处理字符串或平文本,所以需要通过一种编码方式将其处理为数值,Word Embedding 就是这样将文本处理成数值的一类方法。
2. 不同的Word Embedding 类型
2.1. 基于频率的Word Embedding
2.1.1 Count Vectors
假设一个一个语料库C有D个文本片段{d1,d2,d3,…dD} 以及N个从语料库C中提取的token。这N个token将会形成我们的词典,这样我们设定的Count Vector 大小便是 DxN。在矩阵M中,每行都包含着每个文本片段的token出现的频率。
让我们通过一个简单的例子来理解。
D1: He is lazy boy. She is also lazy.
D2: Neeraj is a lazy person.
假设我们的语料库就仅有这两句话组成,那么我们的词典即为[‘He’,’She’,’lazy’,’boy’,’Neeraj’,’person’]。这里,D=2,N=6。
那么我们2x6的矩阵将被表示为:
He | She | lazy | boy | Neeraj | person | |
---|---|---|---|---|---|---|
D1 | 1 | 1 | 2 | 1 | 0 | 0 |
D2 | 0 | 0 | 1 | 0 | 1 | 1 |
这样,每一纵列便可被认为是每个单词的词向量。比如,lazy的词向量就是[2,1],其他单词的词向量以此类推。在上图这个矩阵中,行对应着语料库中的一个个文本片段,列对应着词典中的一个个token。我们要像这样阅读这个矩阵。D2 包含了’lazy’:一次,’Neeraj’:一次以及’person’:一次。
然而,在准备上面这个矩阵M时,可能有一些变体。这些变体的变化之处在于:
- 准备词典的方式
你可以会疑惑为何准备词典时我们也要加以变动?事实上,在实际应用中,我们的语料库可能包含着成百上千个文本片段。那么我们就需要从这成百上千的文本片段中提取出独特的token,那么这势必会导致我们所得出的例如上图的矩阵非常稀疏,且计算时非常低效。因此,一个可选的解决方法是,我们将基于频率选取比方前10000个单词来作为我们的词典,然后再基于这个词典来构建我们的矩阵。
- 计算单词频次的方式
在计数时,其实我们有两种选择,一种是计算频率,即一个单词在这个文本中的次数,一种是计算是否出现,即一个单词如果在这个文中出现则为1,否则为0。但是一般情况下,我们还是倾向于使用前者。
下图是矩阵M的示意图,方便你理解:
2.1.2 TF-IDF vectorization
TF-IDF vectorization 是另一种基于频率的表示方式,但是它与 Count Vector不同在于它所考虑的不仅仅是一个单词在单个文本片段中的出现频次,而是考虑它在整个语料中的出现频率。所以,这背后有何合理性呢?让我们试着理解这一点。
比较常见的单词,例如”is”,”the”,”a”等和那些对于文本片段更为重要的片段相比往往出现得更为频繁。比如”the”这种单词在各个文本片段中都有出现,而”Harry Potter”可能只出现在《哈利波特》这部小说有关的文本片段里,但是对于这些片段来说,”Harry Potter”显然比”the”更重要,因为它把这些文本和其他文本区别开。于是我们希望降低这些较为常见的单词的权重并且更加重视那些文本片段中独特的单词。
TF-IDF就可以做到上面这一点。那么TD-IDF是如何工作的呢?
如下图所示,假设我们有这样一个表格,第一列是文本中的token,第二列是出现的频次。
首先,我们先来定义一下TF-IDF相关的一些术语:
- TF:文本中term T出现的次数/文本的term总数
因此,TF(This,Doucument1)=1/8,TF(This,Document2)=1/5。
TF表示了这个单词对这个文本的贡献程度,比如说和文本更为相关的单词,它的TF值会比较大,因为它会更高频地出现在文本中。
- DF:log(语料库中的文本总数/语料库中含有term T的文本数)
因此,IDF(this)=log(2/2)=0。
理论上来说,如果一个单词在语料库所有的单词中都出现了,那么可能这个单词对于某个或某些特定的文本并不重要,即是我们所说的那类比较常见的单词。但是如果一个单词只出现语料库的一个子集的文本中出现,那么这个单词对于那些文本具有一定的相关性。比如IDF(Messi)=log(2/1)=0.301。
由此可见,对于文本片段1而言,TF-IDF方法狠狠地处罚了”this”但是却给予”Messi”更高的权重。因此这个方法能够帮助我们更好的理解”Messi”是文本片段1的一个重要单词。
2.1.3 具有固定上下文窗口的共现矩阵
指导思想:相似的单词往往一起出现并且具有相似的文本环境。比如”Apple is a fruit”,”Mango is a fruit”,苹果和芒果倾向于有一个相似的上下午,如”fruit”。
在我深入一个共现矩阵是如何构建的细节之前,我们有必要先理清两个概念。
- Co-occurence:对于一个给定的语料库,一对单词的共现,比方说w1和w2的共现,就是在一个上下文窗口中它们共同出现的次数。
- Context Window:上下文窗口的参数由数字和方向设定。我们举个例子来帮助理解。
Quick | brown | fox | jump | over | the | lazy | dog |
---|---|---|---|---|---|---|---|
Quick | brown | fox | jump | Over | The | lazy | dog |
这个表格第一行的斜体是fox的长度为2的上下文窗口,第二行的斜体是over的长度为2的上下文窗口。
现在,我们编一个用来计算共现矩阵的语料库。
语料库:He is not lazy. He is intelligent. He is smart.
让我们通过看上面两个红、蓝着色的例子来理解共现矩阵。
红色格子所表示的,是”He”和”is”在长度为2的上下文窗口中出现的次数,红色格子中的数字为4,我们可以通过下面的表格可视化这个计数过程。(即出现无需紧挨着,只要都在窗口中,即使顺序颠倒,都是可以的)。
蓝色格子所表示的,是”lazy”和”intelligent”在长度为2的上下文窗口中出现的次数,其中数字为0,表示它们从不曾同时出现在一个上下文窗口中。
共现矩阵的变体
假设语料库中有V个独特的单词,那么我们的词汇长度即为V。下面给出了共现矩阵的两种不同变体:
- 大小为VxV的共现矩阵。但是由于这样的矩阵太大而难于计算,所以实际中这类建模并不被看好。
- 大小为VxN的共现矩阵。N表示去除掉停用词等不相关词汇后的V的一个自己。但是这类建模也依然很大且难于计算。
这里要强调一点,共现矩阵并非是我们广泛使用的词向量。相反,这类共现矩阵常常与诸如PCA,SVD这样的技术组合使用在因素分解上。而这些因素分解的组合构成了词向量表示。
说得更明白些,你在下面VxV的共现矩阵上使用了PCA,你会得到V个主元素。如此,你可以从这V个元素中选出k个。因此,你讲得到一个Vxk的新剧证。这样,虽然一个单词是由k维表示的而不是V维表示的,但是它依然能捕捉到几乎同样的意义。
因此,PCA背后的操作实际上就是讲共现矩阵拆解为三个矩阵,U,S和V。
共现矩阵的优点
- 它蕴含了单词之间的语义联系。比如”男人”和”女人”会比”男人”和”苹果”更近。
- 它的核心在于使用SVD来创造出比现存方法更准确的词向量表示。
- 它使用因子分解,因子分解是一个良定义问题并且可以被有效解决。
- 它只要被计算一次,之后任何时候都可以被使用。在这个意义上,它比其他方法更快。
共现矩阵的缺点
- 它需要巨大的内存去存储。
2.2 基于预测的word embedding
前面所说的基于频率的word embedding有各种各样的局限。而后Mitolov等人将word2vec介绍到nlp的各个领域中,使得基于预测的word embedding走上历史舞台。这些方法是基于预测的,也就是说它们会给出各个单词的概率。它们在词汇相似度的任务上表现得非常好,甚至能达到King -man +woman = Queen这样的神奇效果。下面,我们就来看看word2vec具体是如何得出词向量的。
word2vec并不是一个单独的算法,它是由CBOW和Skip-gram模型组合而成的。这两个模型都是由词到词的浅层神经网络组成的。它们所学习的权重将成为单词的向量表示。接下来,我们就分别介绍这两种模型。
2.2.1 CBOW 连续词袋模型
CBOW是基于语境(文本上下文)来预测出一个单词的概率。这个语境可能是一个单词或者一组词。但为了介绍的简单,我们这边以一个单词作为语境并一次来预测一个目标词汇。
假设我们有一个语料库C=”Hey, this is sample corpus using only one context word.”。并且我们已经定义了上下文窗口大小为1。这个语料库将会被转换成下图所示的训练集合。输入如下图所示。下图中右边的矩阵包含了左边的输入的独热编码。
比如说is的目标的输入为[0001000000]。
上图所显示的矩阵将会被送入一个由三层组成的浅层神经网络:一个输入层,一个隐藏层和一个输出层。输出层会使用softmax函数,softmax函数是一个用于分类预测的常用函数,这个函数得出的各个类别的数值总和为1。
流程是这样的:
- 输入层和目标层都是由1xV的独热编码组成,这里V=10。
- 这里有两套权重,一套是输入层和隐藏层之间的权重,一套是隐藏层和输出层之间的权重。input-hidden 层矩阵大小为VxN, hidden-output 那层的矩阵大小为NXV :这里,N指的是我们选择用来表达单词的维度。它是任意的,并且是神经网络的一个超参数。并且,N是也是隐藏层的节点数,这里,我们设N=4。
- 任意一层之间都不存在激活函数。
- 输入与 input-hidden层权重的乘积被称为 hidden activation。
- Hidden input 与hidden-output层权重相乘,得到输出。
- 输出层和目标之间的误差将会被用来进行反向传播,以调整weights。
- 在隐藏层和输出层之间权重将会成为词向量。
上面的流程是针对于上下文窗口为1的,下图显示了上下文窗口大于1的情况。
下图是为了更好理解这个结构的矩阵图例。
如上图所示,我们要使用3个 context word去预测目标单词的概率。输入层是3个[1xV]的向量,而输出是一个[1xV]。剩下的构造和1-context的CBOW是一样的。
但是在隐藏层中,3-context word的模型不再是简单复制输入,而是要进行一个平均。我们可以通过上面的图来理解这一点,如果我们有3个context word, 那么我们将会有3个 初步的hidden activation 然后最后平均得到最终的 hidden activiation。
那么CBOW和一般的MLP之间有何不同呢?
- CBOW的目标函数和MLP不同,CBOW是目标函数负的最大似然。
- 误差梯度不一样,因为MLP以sigmoid作为激活函数,而CBOW一般是线性激活。
CBOW的优点:
- 基于概率的,更符合实际;
- 占用内存小。
CBOW的缺点:
- CBOW是利用单词的语境来表示单词的,但是对于多义词而言,比如苹果既是水果也是一家公司,但是由于CBOW将这个文本都考虑进去,所以苹果被表示在水果和公司之间了。
- 从头训练一个CBOW若没有很好优化的话将训练很久。
2.2.2 Skip-Gram model
Skip-gram 的类型与CBOW一样,但是它的结构是反过来的,它是基于给定单词去预测单词的上下文。我们依然用讲解CBOW时使用的语料。
Skip-gram的输入和1-context的CBOW 模型很类似。并且隐藏层的activitiaon也是一样的。不同的仅仅是目标变量。因为我们已经在单词两边都定义了一个长度为1的上下文窗口,所以我们会有两个独热编码的目标变量和两个相应的输出。
而这两个目标变量的误差将会被分别计算,然后将两个误差加起来进行反向传播。
Skip-Gram 模型的优点
- 可以抓住一个单词的多个义项。
- 使用负采样的Skip-Gram模型会比其他方法更高效。
Skip-Gram模型的缺点
- 依赖语料库的大小
- 采样是对统计数据的低效利用